package com.danbay.cloud.device.service;

import com.danbay.cloud.base.constants.Const;
import com.danbay.cloud.base.constants.DeviceType;
import com.danbay.cloud.device.api.constants.DeviceConstant;
import com.danbay.cloud.device.api.dto.DeviceRegDto;
import com.danbay.cloud.device.api.service.IDeviceRegService;
import com.danbay.cloud.device.client.DeviceAccessClient;
import com.danbay.cloud.device.constant.DeviceCommonConstant;
import com.danbay.cloud.device.entity.CenterControl;
import com.danbay.cloud.device.entity.DeviceCollector;
import com.danbay.cloud.device.entity.DeviceInfo;
import com.danbay.cloud.device.entity.EnergyDevice;
import com.danbay.cloud.device.mapper.CenterControlMapper;
import com.danbay.cloud.device.mapper.DeviceCollectorMapper;
import com.danbay.cloud.device.mapper.DeviceInfoMapper;
import com.danbay.cloud.device.mapper.EnergyDeviceMapper;
import com.danbay.framework.exception.BusinessException;
import com.danbay.framework.utils.BeanValidator;
import com.danbay.framework.utils.DateUtils;
import com.danbay.framework.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;

/**
 * 设备管理服务
 *
 * @author SJG
 * @date 2017/10/21
 */
@Slf4j
@Service
public class DeviceRegService implements IDeviceRegService {

    private final CenterControlMapper centerControlMapper;
    private final EnergyDeviceMapper energyDeviceMapper;
    private final DeviceCacheService deviceCacheService;
    private final DeviceInfoMapper deviceInfoMapper;
    private final DeviceCollectorMapper deviceCollectorMapper;
    private final DeviceAccessClient deviceAccessClient;

    @Autowired
    public DeviceRegService(CenterControlMapper centerControlMapper, EnergyDeviceMapper energyDeviceMapper, DeviceCacheService deviceCacheService,DeviceInfoMapper deviceInfoMapper,
                            DeviceCollectorMapper deviceCollectorMapper,DeviceAccessClient deviceAccessClient) {
        this.centerControlMapper = centerControlMapper;
        this.energyDeviceMapper = energyDeviceMapper;
        this.deviceCacheService = deviceCacheService;
        this.deviceInfoMapper = deviceInfoMapper;
        this.deviceCollectorMapper = deviceCollectorMapper;
        this.deviceAccessClient = deviceAccessClient;
    }


    /**
     * 设备第一次入网时，中控、水电表向云端注册。兼容PA与采集器
     *
     * @param regDto 注册参数
     * @throws BusinessException 业务异常
     */
    @Override
    public String register(DeviceRegDto regDto) throws BusinessException {
        //验证参数
        BeanValidator.valid(regDto);
        //中控注册
        if (regDto.isGateway()) {
            return registerCenterControl(regDto);
        }
        //其它设备注册
        if (StringUtils.isBlank(regDto.getFatherDevId())) {
            throw new BusinessException("设备所属父级设备ID为空");
        }
        //取原有的中控信息
        CenterControl centerControl = centerControlMapper.selectOne(CenterControl.builder().deviceId(regDto.getFatherDevId()).build());
        if (null == centerControl) {
            throw new BusinessException("未找到该设备:" + regDto.getMac() + "关联的中控:" + regDto.getFatherDevId());
        }
        //设备类型
        DeviceType deviceType = DeviceType.parse(regDto.getSn());
        //无线电表或水表
        if (deviceType == DeviceType.EM_METER || deviceType == DeviceType.WATER_METER) {
            return registerMeterDevice(regDto, centerControl.getId());
        }
        //门锁
        if (deviceType == DeviceType.LOCK_IN || deviceType == DeviceType.LOCK_OUT) {
            return registerLock(regDto,centerControl.getId());
        }
        //PA
        if (deviceType == DeviceType.PA){
            return registerPA(regDto);
        }
        //采集器
        if (deviceType == DeviceType.COLLECTOR){
            return registerCollector(regDto,centerControl.getId());
        }
        return null;

    }

    /**
     * 注册中控
     *
     * @param regDto 注册信息
     */
    private String registerCenterControl(DeviceRegDto regDto) {
        //查询已有的中控
        CenterControl centerControl = centerControlMapper.selectOne(
                CenterControl.builder().macAddress(regDto.getMac()).build());
        if (centerControl != null) {
            log.info("中控 {} 已注册,更新注册信息", centerControl.getDeviceId());
            //已注册，修改注册信息
            centerControlMapper.updateById(
                    CenterControl.builder()
                            .id(centerControl.getId())
                            .name(regDto.getSn())
                            .macAddress(regDto.getMac())
                            .version(regDto.getVer())
                            .remoteAddr(regDto.getIp())
                            .address(regDto.getIp())
                            .hasDelete(DeviceCommonConstant.DEVICE_UN_DELETED)
                            .build()
            );
            //更新redis缓存
            deviceCacheService.cacheRegInfo(regDto, centerControl.getDeviceId());
            return centerControl.getDeviceId();
        }
        //生成设备id
        String deviceId = generateDeviceId(regDto.getMac());
        //未注册
        centerControlMapper.insert(
                CenterControl.builder()
                        .name(regDto.getSn())
                        .macAddress(regDto.getMac())
                        .version(regDto.getVer())
                        .address(regDto.getIp())
                        .createTime(DateTime.now().toDate())
                        .remoteAddr(regDto.getIp())
                        .address(regDto.getIp())
                        .status(Const.BOOL_STRING_FALSE)
                        .addstatus(Const.BOOL_STRING_FALSE)
                        .hasDelete(DeviceCommonConstant.DEVICE_UN_DELETED)
                        .deviceId(deviceId)
                        .build()
        );
        //添加到redis缓存
        deviceCacheService.cacheRegInfo(regDto, deviceId);
        return deviceId;
    }

    /**
     * 注册无线水电表
     *
     * @param regDto 注册信息
     */
    private String registerMeterDevice(DeviceRegDto regDto, Long centerControlId) {
        //查询已注册的设备
        EnergyDevice energyDevice = energyDeviceMapper.selectOne(
                EnergyDevice.builder().address(regDto.getMac()).build());
        //设备类型
        DeviceType deviceType = DeviceType.parse(regDto.getSn());
        //未注册
        if (energyDevice == null) {
            //生成设备id
            String deviceId = generateDeviceId(regDto.getMac());
            energyDeviceMapper.insert(
                    EnergyDevice.builder()
                            .name(regDto.getSn())
                            .deviceId(deviceId)
                            .address(regDto.getMac())
                            .addTime(DateTime.now().toDate())
                            .hasDelete(Const.BOOL_STRING_FALSE)
                            .addStatus(Const.BOOL_INT_FALSE)
                            .deviceNum(regDto.getVer())
                            .deviceType(deviceType.value() + "")
                            .type(deviceType == DeviceType.WATER_METER ? Const.ENERGY_DEVICE_TYPE_WATERMETER : Const.ENERGY_DEVICE_TYPE_AMMETER)
                            .centerControlId(centerControlId)
                            .build()
            );
            //添加到redis缓存
            deviceCacheService.cacheRegInfo(regDto, deviceId);
            return deviceId;
        }

        //已经注册
        EnergyDevice modifiedDevice = EnergyDevice.builder()
                .id(energyDevice.getId())
                .deviceId(energyDevice.getDeviceId())
                .name(regDto.getSn())
                .address(regDto.getMac())
                .deviceNum(regDto.getVer())
                .centerControlId(centerControlId)
                .build();

        // 拆到了另外一个中控；
        if (energyDevice.getCenterControlId()==null || !energyDevice.getCenterControlId().equals(centerControlId)) {
            //设备迁移了，清空合同信息，用户信息，房间信息；
            modifiedDevice.setHouseInfoId(null);
            modifiedDevice.setUser(null);
            modifiedDevice.setContractInfo(null);
            modifiedDevice.setAddStatus(Const.BOOL_INT_FALSE);

            //记录迁移日志
            log.warn("设备发生迁移,设备:{}从中控:{}迁移到中控:{}", energyDevice.getId(), energyDevice.getCenterControlId(), centerControlId);
        }
        //更新
        energyDeviceMapper.updateById(modifiedDevice);
        //更新redis缓存
        deviceCacheService.cacheRegInfo(regDto, energyDevice.getDeviceId());
        return energyDevice.getDeviceId();
    }

    /**
     * 门锁注册
     * @param regDto
     * @param centerControlId
     * @return
     */
    private String registerLock(DeviceRegDto regDto,Long centerControlId) {
        //1.查询已有设备
        DeviceInfo deviceInfo = deviceInfoMapper.selectOne(DeviceInfo.builder().macAddress(regDto.getMac()).build());
        if (null == deviceInfo) {
            //2.第一次注册 2.1:生成设备ID,2.2:插入记录,2.3:缓存注册信息
            String deviceId = generateDeviceId(regDto.getMac());
            deviceInfoMapper.insert(DeviceInfo.builder().macAddress(regDto.getMac())
                                                        .deviceId(deviceId)
                                                        .remoteAddr(regDto.getIp())
                                                        .deviceVersion(regDto.getVer())
                                                        .deviceModel(regDto.getSn())
                                                        .addStatus(DeviceConstant.DEVICE_LOCK_ADD_STATUS_NO)
                                                        .name(regDto.getSn())
                                                        .centerControl(centerControlId)
                                                        .deviceTime(new Date())
                                                        .deviceType(DeviceConstant.DEVICE_LOCK_TYPE_OUT_DOOR)
                                                        .status(DeviceConstant.DEVICE_LOCK_ON_LINE)
                                                        .addTime(new Date())
                                                        .hasDelete(DeviceConstant.DEVICE_LOCK_HAS_DELETE_NO)
                                                        .build());
            deviceCacheService.cacheRegInfo(regDto, deviceId);
            return deviceId;
        }
        if (!deviceInfo.getCenterControl().equals(centerControlId)) {
            //设备迁移,重新置空值
            deviceInfo.setHouseInfoId(null);
            deviceInfo.setAddStatus(DeviceCommonConstant.DEVICE_UN_ADD);
            deviceInfo.setCenterControl(centerControlId);
            deviceInfo.setContractInfo(null);
            deviceInfo.setContractNum(null);
            //记录设备迁移日志
            log.warn("设备发生迁移:设备{}从中控:{}迁移到中控:{}",deviceInfo.getDeviceId(),deviceInfo.getCenterControl(),centerControlId);
        }
        deviceInfoMapper.updateById(deviceInfo);
        deviceCacheService.cacheRegInfo(regDto, deviceInfo.getDeviceId());
        return deviceInfo.getDeviceId();
    }

    /**
     * PA注册
     *   说明:
     * @param deviceRegDto
     * @return
     */
    private String registerPA(DeviceRegDto deviceRegDto){
        //生成设备ID
        String deviceId = generateDeviceId(deviceRegDto.getMac());
        deviceCacheService.cacheRegInfo(deviceRegDto,deviceId);
        return deviceId;
    }

    /**
     * 采集器注册
     * @param deviceRegDto
     * @param centerControlId
     * @return
     */
    private String registerCollector(DeviceRegDto deviceRegDto,Long centerControlId) throws BusinessException{
        //1.查询已有设备
        DeviceCollector collector = deviceCollectorMapper.selectOne(DeviceCollector.builder().macAddress(deviceRegDto.getMac()).build());
        if (null == collector) {
            //第一次注册
            //2.生成设备ID
            String deviceId = generateDeviceId(deviceRegDto.getMac());
            //3.插入信息
            deviceCollectorMapper.insert(DeviceCollector.builder()
                                                        .centerControl(centerControlId)
                                                        .address(deviceRegDto.getIp())
                                                        .name(deviceRegDto.getSn())
                                                        .deviceModel(deviceRegDto.getSn())
                                                        .version(deviceRegDto.getVer())
                                                        .status(DeviceCommonConstant.DEVICE_ONLINE_STATE)
                                                        .hasDelete(DeviceCommonConstant.DEVICE_UN_DELETED)
                                                        .addStatus(DeviceCommonConstant.DEVICE_UN_ADD)
                                                        .addTime(new Date())
                                                        .meterNum(DeviceCommonConstant.DEVICE_COLLECTOR_ORIGIN_COUNT)
                                                        .deviceType(DeviceCommonConstant.parseDeviceType(deviceRegDto.getSn()))
                                                        .build());
            //4.缓存注册信息
            deviceCacheService.cacheRegInfo(deviceRegDto, deviceId);
            return deviceId;
        }
        //已经注册.
        if (!centerControlId.equals(collector.getCenterControl())) {
            //设备迁移,重新设置值
            collector.setCenterControl(centerControlId);
            collector.setHouseInfoId(null);
            collector.setAddStatus(DeviceCommonConstant.DEVICE_UN_ADD);
            collector.setContractInfo(null);
            collector.setRoomId(null);
            //记录设备迁移日志
            log.warn("设备发生迁移:设备{}从中控:{}迁移到中控:{}", collector.getDeviceId(), collector.getCenterControl(), centerControlId);
        }
        collector.setAddress(deviceRegDto.getIp());
        deviceCollectorMapper.updateById(collector);
        deviceCacheService.cacheRegInfo(deviceRegDto, collector.getDeviceId());
        //获取采集器下接档案数
        deviceAccessClient.getCount(collector.getDeviceId());
        return collector.getDeviceId();
    }

    /**
     * 生成设备id
     *
     * @param mac 设备mac或唯一码长度不超过16位（不包含非数字和字母）
     *            规则：12位的(yyyyMMddHHmmss)16进制串+mac,mac小于16位时后面补0
     * @return 32位id
     */
    public static String generateDeviceId(String mac) {
        //取yyyyMMddHHmmss的16进制串
        String timeStr = DateUtils.now(DateUtils.YMDHMS2);
        Long timeLong = Long.parseLong(timeStr);
        timeStr = Long.toHexString(timeLong);
        //去除非数字和字母的字符
        mac = mac.replaceAll("[^0-9A-Za-z]", "").toLowerCase();
        //使用0填充到20位
        mac = StringUtils.rightPad(mac, 32 - timeStr.length(), '0');
        //12+20
        return timeStr + mac;
    }
}
